#include "FieldAccess.h"
#include "ClassDefinition.h"
#include "../Exceptions.h"
#include "../GeneralVisitor.h"

FieldAccess::FieldAccess(TreeNode* iObjectVariable, string iFieldName)
{
    this->fObjectVariable = iObjectVariable;
    this->fFieldName = iFieldName;
}

FieldAccess::~FieldAccess()
{
    delete this->fObjectVariable;
}

void FieldAccess::CheckVariables(set<string>& oVariables, string iParentName)
{
    this->fObjectVariable->CheckVariables(oVariables, iParentName);
}

ExpressionType* FieldAccess::GetType(map<string, ExpressionType*>&, string)
{
    // pri semanticke kontrole typy fieldu neresime
    return new ExpressionType(Unresolved);
}

void FieldAccess::CheckExpressionTypes(map<string, ExpressionType*>& iVarTypes, string iParentName)
{
    if(!this->fObjectVariable->IsClassField())
    {
        ExpressionType* lType = this->fObjectVariable->GetType(iVarTypes, iParentName);

        // OK, neres to
        if(lType->fResolveTypeAtRuntime)
        {
            delete lType;
            return;
        }

        string lName = this->fObjectVariable->GetVarName();

        // hele, vim co to je a neni to objekt - jak asi chci pristupovat k fieldu neceho, co neni objekt???
        // IDEA: pokud by se delaly nejake built-in objekty, tady se to musi upravit (a nebo taky ne)
        if(lType->fType != UserDefinedObject)
        {
            delete lType;
            throw VariableIsNotAnObjectException(lName, iParentName);
        }

        // zkontroluj, jestli tam ten field skutecne existuje
        if(!lType->fClassDef->FieldExists(this->fFieldName))
        {
            delete lType;
            throw FieldNotDeclaredException(this->fFieldName, lName, iParentName);
        }

        delete lType;
    }
    else
        // samotna objectVariable je FieldAccess -> aplikuj kontrolu rekurzivne, az dojdes na uplny zacatek
        // priklad: a.b.c.d = "eee";
        // bude se kontrolovat existence fieldu jenom v promenne "a", u tech dalsich uz by to bylo pri semanticke kontrole
        // hodne tezke a bude se to delat az za behu
        this->fObjectVariable->CheckExpressionTypes(iVarTypes, iParentName);
}

void FieldAccess::Accept(GeneralVisitor* iVisitor)
{
    iVisitor->Visit(this);
}
